package Metier.Controleurs;

import Donnees.DaoHDP;
import Donnees.DaoLotVitrine;
import Donnees.DaoPerte;
import Donnees.DaoProduit;
import Donnees.DaoStock;
import Donnees.DaoVente;
import Metier.Objets.Commande;
import Metier.Objets.HeurePointe;
import Metier.Objets.LotVitrine;
import Metier.Objets.ModePaiement;
import Metier.Objets.Perte;
import Metier.Objets.Produit;
import Metier.Objets.Stock;
import java.sql.SQLException;
import java.sql.Timestamp;
import Metier.Utils.DateUtils;
import Presentation.FenetrePrincipale;
import Presentation.Onglet;
import Presentation.OngletVendeur;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class GestionVitrine {

    private final DaoLotVitrine daoVitrine;
    private final DaoPerte daoPerte;
    private final DaoProduit daoProduit;
    private final DaoHDP daoHDP;
    private final DaoStock daoStock;

    private final Onglet onglet;

    private final ResourceBundle venteBundle;

    /**
     * constructeur GestionVitrine minimaliste
     * @param onglet
     */
    public GestionVitrine(Onglet onglet){
        this.daoVitrine = new DaoLotVitrine();
        this.daoPerte = new DaoPerte();
        this.daoProduit = new DaoProduit();
        this.daoHDP = new DaoHDP();
        this.daoStock = new DaoStock();
        this.onglet = onglet;
        if (onglet == null) {
            this.venteBundle = ResourceBundle.getBundle("ressources/Cuisson/Cuisson", Locale.FRENCH);
        } else {
            this.venteBundle = ResourceBundle.getBundle("ressources/Vente/Vente", onglet.getFP().getLocale());
        }
    }

    /**
     * Renvoie le model de la liste principale
     * @return Le model de la liste principale
     */
    public DefaultListModel getContenuListPrincipale() {
        DefaultListModel listModel = new DefaultListModel();
        try {
            List<Produit> list = daoProduit.chercher();
            for (Produit p : list) {
                listModel.addElement(p);
            }
        } catch (SQLException e){
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errGetListPrincipale"));
            e.printStackTrace();
        }
        return listModel;
    }

    /**
     * Renvoie le model du tableau Produit
     * @param p Produit concerné
     * @param list List des LotVitrine
     * @return Le model du tableau Produit
     */
    public DefaultTableModel getTableProduitModel(Produit p, List<LotVitrine> list) {
        DefaultTableModel tm = new DefaultTableModel() {
            @Override
            public boolean isCellEditable(int row, int column) {
                return column == 3 || column == 4;
            }
        };
        tm.addColumn(this.venteBundle.getString("vente.nomlot"));
        tm.addColumn(this.venteBundle.getString("vente.quantite"));
        tm.addColumn(this.venteBundle.getString("vente.peremption"));
        tm.addColumn(this.venteBundle.getString("vente.commander"));
        tm.addColumn(this.venteBundle.getString("vente.jeterlot"));
        tm.addColumn("id");
        Object[] rowdata = new Object[6];
        for (LotVitrine l : list) {
            if (l.getProduit().equals(p) && l.getQuantite() > 0) {
                rowdata[0] = l.getNom();
                rowdata[1] = l.getQuantite();
                long timeleft = DateUtils.secondsLeft(l.getDatePeremption());
                if (timeleft > 0) {
                    rowdata[2] = DateUtils.secondsToMinuteAndSeconds(timeleft);
                    rowdata[3] = this.venteBundle.getString("vente.commander");
                } else {
                    rowdata[2] = this.venteBundle.getString("vente.perime");
                    rowdata[3] = "perime";
                }
                rowdata[4] = this.venteBundle.getString("vente.jeterlot");
                rowdata[5] = l.getId();
                tm.addRow(rowdata);
            }
        }
        return tm;
    }

    /**
     * Renvoie le model du tableau stock
     * @param p Produit concerné
     * @return Model du tableau stock
     */
    public DefaultTableModel getTableStockModel(Produit p) {
        List<Stock> stocks = this.getStocks(p);
        DefaultTableModel tm = new DefaultTableModel();
        tm.addColumn(venteBundle.getString("vente.peremption"));
        tm.addColumn(venteBundle.getString("vente.quantite"));
        tm.addColumn("stock");
        tm.addColumn("date");
        Object[] rowdata = new Object[4];
        for (Stock s : stocks) {
            long timeleft = DateUtils.secondsLeft(new Timestamp(s.getDatePeremption().getTime()));
            rowdata[0] = timeleft > 0 ? DateUtils.secondsToMinuteAndSeconds(timeleft) : venteBundle.getString("vente.perime");
            rowdata[1] = s.getQuantite();
            rowdata[2] = s;
            rowdata[3] = s.getDatePeremption();
            tm.addRow(rowdata);
        }
        return tm;
    }

    /**
     * Renvoie la liste des Produits périmés
     * @param oldListAlertes Ancienne liste de produits périmés
     * @return Liste des Produits périmés
     */
    public List<Produit> getAlertesPeremption(List<Produit> oldListAlertes) {
        List<Produit> listAlertes = new ArrayList<>();
        List<LotVitrine> lotsVitrine = this.getLotsVitrine();
        for (LotVitrine lot : lotsVitrine) {
            long timeleft = DateUtils.secondsLeft(lot.getDatePeremption());
            if (lot.getQuantite() > 0 &&
                    timeleft <= 0 &&
                    !listAlertes.contains(lot.getProduit())) {
                listAlertes.add(lot.getProduit());
            }
        }
        for (Produit p : listAlertes) {
            if (!oldListAlertes.contains(p)) {
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        SwingUtilities.invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                JOptionPane.showMessageDialog(onglet.getFP(),
                                        "<html><p>" +
                                                venteBundle.getString("vente.popupalerte1") +
                                                " " + p + " " +
                                                venteBundle.getString("vente.popupalerte2"),
                                        venteBundle.getString("vente.messagealerte"),
                                        JOptionPane.WARNING_MESSAGE);
                            }
                        });
                    }
                });
                t.start();
            }
        }
        return listAlertes;
    }

    /**
     * Renvoie la liste des boissons en alertes
     * @param oldListAlertes Anciennes boissons en alertes
     * @return Liste des boissons en alertes
     */
    public List<Produit> getAlertesBoissons(List<Produit> oldListAlertes) {
        List<Produit> listAlertes = new ArrayList<>();
        try {
            List<Produit> listBoissons = daoProduit.chercherBoissons();
            List<HeurePointe> listHDP = this.daoHDP.rechercher();
            List<LotVitrine> lotsVitrine = this.getLotsVitrine();
            boolean isHDP = false;
            Calendar g = new GregorianCalendar();
            for (HeurePointe hp : listHDP) {
                if (hp.isEnVigueur(g)) isHDP = true;
            }
            for (Produit p : listBoissons) {
                int seuil = isHDP ? p.getSeuilVitrineHDP() : p.getSeuilVitrine();
                int quantiteVitrine = 0;
                for (LotVitrine lot : lotsVitrine) {
                    if (lot.getProduit().equals(p)) {
                        quantiteVitrine += lot.getQuantite();
                    }
                }
                if (quantiteVitrine <= seuil) {
                    listAlertes.add(p);
                    if (!oldListAlertes.contains(p)) {
                        final int finalQuantiteVitrine = quantiteVitrine;
                        Thread t = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                SwingUtilities.invokeLater(new Runnable() {
                                    @Override
                                    public void run() {
                                        JOptionPane.showMessageDialog(onglet.getFP(),
                                                "<html><p>" +
                                                        venteBundle.getString("vente.popupalerteboisson1") + " " +
                                                        finalQuantiteVitrine + " " +
                                                        p + " " +
                                                        venteBundle.getString("vente.popupalerteboisson2") + " " +
                                                        seuil + " " +
                                                        p + ".</p></html>",
                                                venteBundle.getString("vente.messagealerte"),
                                                JOptionPane.WARNING_MESSAGE);
                                    }
                                });
                            }
                        });
                        t.start();
                    }
                }
            }
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errAlertes"));
            e.printStackTrace();
        }
        return listAlertes;
    }

    /**
     * Valide et ajoute une commande en base
     * @param mode Mode de paiement
     */
    public void validerCommande(ModePaiement mode) {
        float prixTotal = ((OngletVendeur)onglet).getTotalPrice();
        Map<Produit, Integer> hash = new HashMap<>();
        for (int i = 0; i < ((OngletVendeur)onglet).getTableCommandeModel().getRowCount(); i++) {
            Produit p = (Produit)((OngletVendeur)onglet).getTableCommandeModel().getValueAt(i, 5);
            Integer quantite = Integer.valueOf(((OngletVendeur)onglet).getTableCommandeModel().getValueAt(i, 1).toString());
            if (hash.get(p) != null) {
                hash.replace(p, hash.get(p) + quantite);
            } else {
                hash.put(p, quantite);
            }
        }
        Commande c = new Commande(-1, mode, hash, prixTotal);
        DaoVente daoVente = new DaoVente();
        try {
            daoVente.ajouter(c);
            JOptionPane.showMessageDialog(onglet.getFP(),
                    venteBundle.getString("vente.confirmationcommande"),
                    venteBundle.getString("vente.confirmation"),
                    JOptionPane.INFORMATION_MESSAGE);
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errValiderCommande"));
            e.printStackTrace();
        }
        int nb = ((OngletVendeur) onglet).getTableCommandeModel().getRowCount();
        for (int i = 0; i < nb; i++) {
            LotVitrine lot = this.getLot((int)((OngletVendeur)onglet).getTableCommandeModel().getValueAt(i, 3));
            if (lot != null && lot.getQuantite() <= 0) {
                this.supprimerLot(lot);
            }
        }
        for (int i = 0; i < nb; i++) {
            ((OngletVendeur) onglet).getTableCommandeModel().removeRow(0);
        }
        ((OngletVendeur) onglet).getLblTotal().setText("0");
    }

    /**
     * Ajoute un LotVitrine
     * @param lot LotVitrine à ajouter
     * @return LotVitrine ajouté
     */
    public LotVitrine ajouterLotVitrine(LotVitrine lot) {
        try {
            lot = this.daoVitrine.ajouter(lot);
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errAjoutLotVitrine"));
            e.printStackTrace();
        }
        return lot;
    }

    /**
     * Ajout une LotVitrine de boisson
     * @param p Boisson
     * @param quantite Quantité du lot
     * @param datePeremption Date de peremption du lot
     * @param s Stock associé
     * @return LotVitrine ajouté
     */
    public LotVitrine ajouterBoissonVitrine(Produit p, int quantite, Date datePeremption, Stock s) {
        LotVitrine lot = null;
        try {
            int left = s.getQuantite() - quantite;
            if (left > 0) {
                s.setQuantite(s.getQuantite() - quantite);
                this.daoStock.modifier(s);
            } else {
                this.daoStock.supprimer(s);
            }
            lot = new LotVitrine(p, quantite, datePeremption);
            lot = this.ajouterLotVitrine(lot);
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errAjoutBoissonVitrine"));
            e.printStackTrace();
        }
        return lot;
    }

    /**
     * renvoie la liste des lot en vitrine 
     * @return liste des Lot en vitrine
     */
    public List<LotVitrine> getLotsVitrine(){
        List<LotVitrine> liste = new ArrayList<>();
        try {
            liste = this.daoVitrine.chercher();
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errGetLotsVitrine"));
            e.printStackTrace();
        }
        return liste;
    }
    
    /**
     * renvoie le lot correspondant a l'id
     * @param id
     * @return le lot correspondant a l'id et null si ce lot n'est pas trouvé
     */
    public LotVitrine getLot(int id){
        LotVitrine lot = null;
        try {
            lot = this.daoVitrine.chercher(id);
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errGetLotVitrine"));
            e.printStackTrace();
        }
        return lot;
    }

    /**
     * Renvoie les Stock d'un Produit
     * @param p Produit concerné
     * @return Stock du Produit
     */
    private List<Stock> getStocks(Produit p) {
        return new GestionStock(onglet).getStock(p);
    }

    /**
     * retire une certaine quantite d'un produit a un lot
     * @param lot
     * @param quantite 
     */
    public void retirerProduit(LotVitrine lot, int quantite) {
        try {
            lot.setQuantite(lot.getQuantite() - quantite);
            this.daoVitrine.modifier(lot);
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errRetirerProduit"));
            e.printStackTrace();
        }
    }

    /**
     * Modifie un LotVitrine
     * @param lot LotVitrine à modifier
     */
    public void modifierLot(LotVitrine lot) {
        try {
            this.daoVitrine.modifier(lot);
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errModifierLot"));
            e.printStackTrace();
        }
    }

    /**
     * Supprime un LotVitrine
     * @param lot LotCuisson à supprimer
     */
    public void supprimerLot(LotVitrine lot) {
        try {
            this.daoVitrine.supprimer(lot);
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errSupprimerLot"));
            e.printStackTrace();
        }
    }
    
    /**
     * supprime un lot de la vitrine et l'ajoute au perte
     * @param idLot
     */
    public void jeterLot(int idLot) {
        LotVitrine lot;
        try {
            lot = daoVitrine.chercher(idLot);
            Perte perte = new Perte(-1, lot.getQuantite(), lot.getProduit(), new Date());
            this.daoPerte.ajouter(perte);
            this.daoVitrine.supprimer(lot);
        } catch (SQLException e) {
            FenetrePrincipale.afficherPopupErreur(venteBundle.getString("vente.errJeterLot"));
            e.printStackTrace();
        }
    }
}
